package com.db.stockexchange.proto;

import java.math.BigDecimal;

import com.db.stockexchange.domain.ExecutionReport;
import com.db.stockexchange.domain.order.Order;
import com.db.stockexchange.domain.order.OrderSide;
import com.db.stockexchange.proto.Protocol.ExchangeMessage;

public class Converter {
	public static Order messageToOrder(ExchangeMessage message) throws ValidationException {
		
		if (!message.hasClientOrderId())
			throw new ValidationException("client order id not specified");
		
		if (!message.hasOrderType())
			throw new ValidationException("order type not specified");
		
		if (!message.hasSide())
			throw new ValidationException("side not specified");
		
		if (!message.hasQuantity())
			throw new ValidationException("quantity not specified");

		if (!message.hasSymbol())
			throw new ValidationException("symbol not specified");
		
		if (message.getOrderType() == ExchangeMessage.OrderType.LIMIT
				&& !message.hasPrice())
			throw new ValidationException("price not specified");
		
		
		OrderSide side = message.getSide() == ExchangeMessage.Side.BUY ?
				OrderSide.BUY :
				OrderSide.SELL;
		
		int clientOrderId = message.getClientOrderId();
		int quantity = message.getQuantity();
		String symbol = message.getSymbol();
		
		try {
			
			if (message.getOrderType() == ExchangeMessage.OrderType.LIMIT) {
				BigDecimal price = new BigDecimal(message.getPrice());
				return new Order(clientOrderId, quantity, symbol, side, price);
			} else {
				return new Order(clientOrderId, quantity, symbol, side);
			}
			

		} catch (NumberFormatException e) {
			throw new ValidationException("price is not a number");
		} catch (IllegalArgumentException e) {
			throw new ValidationException(e.getMessage(), e);
		}
		
	}
	
	public static ExchangeMessage execReportToMessage(ExecutionReport report) {
		ExchangeMessage.Builder messageBuilder = ExchangeMessage.newBuilder()
				.setClientOrderId(report.getClientOrderId())
				.setCumulativeQuantity(report.getFilledQuantity());
		
		messageBuilder.setMessageType(ExchangeMessage.MessageType.EXECUTION_REPORT);
		
		// TODO this looks ugly, but how can it be improved?
		switch (report.getOrderStatus()) {
		case FILLED:
			messageBuilder.setOrderStatus(ExchangeMessage.OrderStatus.FILLED);
			break;
		case NEW:
			messageBuilder.setOrderStatus(ExchangeMessage.OrderStatus.NEW);
			break;
		case PARTIALLY_FILLED:
			messageBuilder.setOrderStatus(ExchangeMessage.OrderStatus.PARTIALLY_FILLED);
			break;
		case REJECTED:
			messageBuilder.setOrderStatus(ExchangeMessage.OrderStatus.REJECTED);
			break;
		}
		
		if (report.getRejectReason() != null)
			messageBuilder.setComment(report.getRejectReason());
		
		if (report.getCounterparty() != null)
			messageBuilder.setCounterparty(report.getCounterparty());
		
		return messageBuilder.build();
	}
}
